using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using SlimDX;
using SlimDX.Direct3D9;

namespace TileGert
{
  /// <summary>
  /// This is a single layer of tiles for multi-layered tilemaps.
  /// </summary>
  public class GertTileLayer
  {
    private GertTile[,] _tiles = null;
    private bool _drawGrid = false;
    private bool _drawCoords = false;
    private bool _drawTiles = true;
    private int _tileSize = 32;
    private GertGame _game = null;
    private SlimDX.Direct3D9.Font fDefaultFont = null;
    private GertColor _gridColor = GertColor.Red;

    /// <summary>
    /// Creates a new tile layer for the given game with the given  dimensions.
    /// </summary>
    /// <param name="game">The game this tile layer is associated with.</param>
    /// <param name="width">The width of the tilemap in tiles.</param>
    /// <param name="height">The height of the tilemap in tiles.</param>
    public GertTileLayer(GertGame game, int width, int height)
    {
      _game = game;
      fDefaultFont = new SlimDX.Direct3D9.Font(_game.Renderer.D3DDevice, SystemFonts.DefaultFont);
      _tiles = new GertTile[width, height];
      InitTiles();
    }

    /// <summary>
    /// Initialzes the internal tiles array.
    /// </summary>
    private void InitTiles()
    {
      for (int y = 0; y < _tiles.GetLength(1); y++)
      {
        for (int x = 0; x < _tiles.GetLength(0); x++)
        {
          _tiles[x, y] = new GertTile();
        }
      }
    }

    /// <summary>
    /// Gets or sets the tile at the position (x, y).
    /// </summary>
    public GertTile this[int x, int y]
    {
      get { return _tiles[x, y]; }
      set { _tiles[x, y] = value; }
    }

    /// <summary>
    /// Determines if a grid is drawn over the tiles (true) or not (false). This is mostly for debugging purposes.
    /// The default is false.
    /// </summary>
    public bool DrawGrid
    {
      get { return _drawGrid; }
      set { _drawGrid = value; }
    }

    /// <summary>
    /// Determines if the coordinates of the tile is drawn in the left upper corner of each tile (true) or not (false).
    /// This is mostly for debugging purposes. The default is false.
    /// </summary>
    public bool DrawCoordinates
    {
      get { return _drawCoords; }
      set { _drawCoords = value; }
    }

    /// <summary>
    /// Determines if the tiles themselfs are drawn (true) or not (false).
    /// This is mostly for debugging purposes. The default is true.
    /// </summary>
    public bool DrawTiles
    {
      get { return _drawTiles; }
      set { _drawTiles = value; }
    }

    /// <summary>
    /// Gets or sets the size of the tiles in pixels. Tiles are rectengular.
    /// The default is 32x32.
    /// </summary>
    public int TileSize
    {
      get { return _tileSize; }
      set { _tileSize = value; }
    }

    /// <summary>
    /// Gets or sets the color of the grid that is drawn if DrawGrid is true.
    /// </summary>
    public GertColor GridColor
    {
      get { return _gridColor; }
      set { _gridColor = value; }
    }

    /// <summary>
    /// Gets the tile at the given pixel based position. Make sure that TileSize is set correctly for this to work!
    /// </summary>
    /// <param name="x">The pixel based x coordinate.</param>
    /// <param name="y">The pixel based y coordinate.</param>
    /// <returns>The tile at the given pixel based position, or <code>null</code> if there is no tile at this position.</returns>
    public GertTile TileAt(int x, int y)
    {
      int tileX = (x + _game.Viewport.Left) / _tileSize;
      int tileY = (y + _game.Viewport.Top) / _tileSize;
      if (tileX >= 0 && tileX < _tiles.GetLength(0) &&
          tileY >= 0 && tileY < _tiles.GetLength(1))
        return _tiles[tileX, tileY];
      else
        return null;
    }

    /// <summary>
    /// Draws the whole tile layer to the screen depending on the viewport of the game.
    /// </summary>
    public void Draw()
    {
      int offsetX = _game.Viewport.Left;
      int offsetY = _game.Viewport.Top;
      int width = _game.Viewport.Width;
      int height = _game.Viewport.Height;

      int firstXTile = GertMisc.Max(offsetX / _tileSize, 0);
      int firstYTile = GertMisc.Max(offsetY / _tileSize, 0);
      int lastXTile = GertMisc.Min((offsetX + width) / _tileSize, _tiles.GetLength(0) - 1) + 1;
      int lastYTile = GertMisc.Min((offsetY + height) / _tileSize, _tiles.GetLength(1) - 1) + 1;

      int xPix = firstXTile * 32 - offsetX;
      int yPix = firstYTile * 32 - offsetY;

      if (_drawTiles || _drawCoords)
      {
        for (int yTile = firstYTile; yTile < lastYTile; yTile++)
        {
          int y = yTile * _tileSize - offsetY;
          for (int xTile = firstXTile; xTile < lastXTile; xTile++)
          {
            int x = xTile * _tileSize - offsetX;

            if (_drawTiles)
            {
              GertTile tile = _tiles[xTile, yTile];

              if (tile != null && tile.Image != null)
                _game.Renderer.DrawSprite(tile.Image, x, y);
            }

            if (_drawGrid)
              _game.Renderer.DrawSprite("tilegert_gridtile", x, y, _gridColor);

            if (_drawCoords)
              fDefaultFont.DrawString(_game.Renderer.D3DSprite, xTile + "/" + yTile, x + 2, y, GertColor.White.ToColor4());
          }
        }
      }
    }

  }
}
